/*
 * Project: Sudoku Explainer
 * Copyright (C) 2006-2007 Nicolas Juillerat
 * 
 * Project: Sudoku Hint Engine for Android
 * Copyright (C) 2010-2013 Emanuel Moecklin
 * 
 * Available under the terms of the Lesser General Public License (LGPL)
 */
package com.onegravity.sudoku.solver.util;

import java.util.BitSet;

public class Potentials extends BitSet {
	
	private static final long serialVersionUID = -9031147559065149138L;
	
	private static final int MIN_BIT = 1;
	private static final int MAX_BIT = 9;

	private long bits;

	@Override
	public void and(BitSet set) {
		if (! (set instanceof Potentials)) throw new IllegalArgumentException("and(BitSet set): set must be of type " + getClass().getSimpleName()); //$NON-NLS-1$
		and((Potentials) set);
	}
	public void and(Potentials set) {
		bits &= set.bits;
	}
	
	@Override
	public void andNot(BitSet set) {
		if (! (set instanceof Potentials)) throw new IllegalArgumentException("andNot(BitSet set): set must be of type " + getClass().getSimpleName()); //$NON-NLS-1$
		andNot((Potentials) set);
	}
	public void andNot(Potentials set) {
		bits &= ~set.bits;
	}
	
	@Override
	public int cardinality() {
		int card = 0;
		long tmp = bits;
		for (int i=0; i<=MAX_BIT; i++, tmp>>>=1) {
			card += (tmp&1);
		}
		return card;
	}
	
	@Override
	public void clear() {
		bits = 0;
	}
	
	@Override
	public void clear(int pos) {
		set(pos, false);
	}
	
	@Override
	public void clear(int fromIndex, int toIndex) {
		for (int i=fromIndex; i<toIndex; i++) {
			set(i, false);
		}
	}
	
	@Override
	public Object clone() {
		Potentials clone = new Potentials();
		clone.bits = bits;
		return clone;
	}
	
	@Override
	public boolean equals(Object obj) {
		if (! (obj instanceof Potentials)) return false;
		return ((Potentials)obj).bits == bits;
	}
	
	@Override
	public void flip(int pos) {
		set(pos, !get(pos));
	}
	
	@Override
	public void flip(int fromIndex, int toIndex) {
		for (int i=fromIndex; i<toIndex; i++) {
			flip(i);
		}
	}
	
	@Override
	public boolean get(int pos) {
		return ((bits>>>pos)&1)==1;
	}
	
	@Override
	public Potentials get(int fromIndex, int toIndex) {
		throw new UnsupportedOperationException ("get(int fromIndex, int toIndex) is not supported"); //$NON-NLS-1$
	}
	
	@Override
	public boolean intersects(BitSet set) {
		if (! (set instanceof Potentials)) throw new IllegalArgumentException("intersects(BitSet set): set must be of type " + getClass().getSimpleName()); //$NON-NLS-1$
		return intersects((Potentials) set);
	}
	public boolean intersects(Potentials set) {
		for (int i=0; i<=MAX_BIT; i++) {
			if (set.get(i) && get(i)) return true; 
		}
		return false;
	}
	
	@Override
	public boolean isEmpty() {
		return bits==0;
	}
	
	@Override
	public int length() {
		int len = 0;
		for (int i=MIN_BIT; i<=MAX_BIT; i++) {
			if (get(i)) len=i+1; 
		}
		return len;
	}
	
	@Override
	public int nextClearBit(int startIndex) {
		long mask = 1<<startIndex;
		for (int i=startIndex; i<=MAX_BIT; i++, mask<<=1) {
			if ((bits&mask)==0) return i; 
		}
		return -1;
	}
	
	@Override
	public int nextSetBit(int startIndex) {
		long mask = 1<<startIndex;
		for (int i=startIndex; i<=MAX_BIT; i++, mask<<=1) {
			if ((bits&mask)!=0) return i; 
		}
		return -1;
	}
	
	@Override
	public void or(BitSet set) {
		if (! (set instanceof Potentials)) throw new IllegalArgumentException("or(BitSet set): set must be of type " + getClass().getSimpleName()); //$NON-NLS-1$
		or((Potentials) set);
	}
	public void or(Potentials set) {
		bits |= set.bits;
	}
	
	@Override
	public void set(int pos) {
		bits |= (1L<<pos);
	}
	
	@Override
	public void set(int pos, boolean value) {
		if (value) {
			bits |= (1L<<pos);
		}
		else {
			bits &= ~(1L<<pos);
		}
	}
	
	@Override
	public void set(int fromIndex, int toIndex) {
		for (int i=fromIndex; i<toIndex; i++) {
			set(i);
		}
	}
	
	@Override
	public void set(int fromIndex, int toIndex, boolean value) {
		for (int i=fromIndex; i<toIndex; i++) {
			set(i, value);
		}
	}
	
	@Override
	public int size() {
		return MAX_BIT+1;
	}
	
	@Override
	public String toString() {
		StringBuffer result = new StringBuffer();
		for (int i=MIN_BIT; i<=MAX_BIT; i++) {
			result.append(get(i)?"1":"0"); //$NON-NLS-1$ //$NON-NLS-2$
		}
		return result.toString();
	}
	
	public void xor(Potentials set) {
		bits ^= set.bits;
	}
}
